package com.zmn.plat.business.impl.price;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.dto.KvDTO;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.plat.business.interfaces.pilot.ChannelPriceBService;
import com.zmn.plat.business.interfaces.price.CommonBService;
import com.zmn.plat.business.interfaces.price.ItemPriceBService;
import com.zmn.plat.business.interfaces.product.ServProductBService;
import com.zmn.plat.business.interfaces.service.item.servicetime.ServServiceTimeBService;
import com.zmn.plat.common.constant.ProductConsts;
import com.zmn.plat.common.dictionary.PlatErrorCodeDict;
import com.zmn.plat.common.dto.price.ItemPriceQuery;
import com.zmn.plat.common.dto.price.ItemTo;
import com.zmn.plat.common.dto.product.item.ItemPriceDIO;
import com.zmn.plat.common.dto.product.item.ItemPriceDRO;
import com.zmn.plat.common.dto.product.pricelist.ProductPriceListDRO;
import com.zmn.plat.common.enums.PilotConfigEnum;
import com.zmn.plat.common.exception.PlatException;
import com.zmn.plat.manager.dictionary.ProductDict;
import com.zmn.plat.model.dto.price.PriceCalDTO;
import com.zmn.plat.model.dto.product.ProductRelationDTO;
import com.zmn.plat.model.entity.category.BaseCategory;
import com.zmn.plat.model.entity.category.BaseCategoryAttributeEnum;
import com.zmn.plat.model.entity.product.ServProduct;
import com.zmn.plat.model.entity.product.tariff.ProductTariffQuery;
import com.zmn.plat.model.entity.product.tariff.item.ProductItemQuery;
import com.zmn.plat.model.entity.servcategory.ServCategory;
import com.zmn.plat.model.entity.service.category.ItemCategory;
import com.zmn.plat.model.entity.service.group.ServiceGroup;
import com.zmn.plat.model.entity.service.item.ServiceItem;
import com.zmn.plat.model.entity.service.tariff.ServiceTariff;
import com.zmn.plat.model.vo.product.tariff.ProductTariffVO;
import com.zmn.plat.services.interfaces.category.BaseCategoryAttributeEnumService;
import com.zmn.plat.services.interfaces.category.BaseCategoryService;
import com.zmn.plat.services.interfaces.product.ServProductService;
import com.zmn.plat.services.interfaces.product.tariff.ProductTariffService;
import com.zmn.plat.services.interfaces.product.tariff.item.ProductTariffGroupItemService;
import com.zmn.plat.services.interfaces.product.tariff.item.city.price.ProductTariffItemCityPriceService;
import com.zmn.plat.services.interfaces.servcategory.ServCategoryService;
import com.zmn.plat.services.interfaces.service.category.ItemCategoryService;
import com.zmn.plat.services.interfaces.service.group.ServiceGroupService;
import com.zmn.plat.services.interfaces.service.item.ServiceItemService;
import com.zmn.plat.services.interfaces.service.item.config.ServiceItemTimeConfigService;
import com.zmn.plat.services.interfaces.service.tariff.ServiceTariffService;
import com.zmn.plat.utils.bean.BeanCopyUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 描述: 项目价格实现类
 *
 * @author guoqiao
 * @since 2021/9/6 13:51
 */
@Slf4j
@Service
public class ItemPriceBServiceImpl implements ItemPriceBService {

    @Resource
    ServiceItemService serviceItemService;
    @Resource
    ServProductService servProductService;
    @Resource
    CommonBService commonBService;
    @Resource
    ProductTariffGroupItemService productTariffGroupItemService;
    @Resource
    ProductTariffItemCityPriceService productTariffItemCityPriceService;
    @Resource
    ServiceTariffService serviceTariffService;
    @Resource
    ServServiceTimeBService serviceTimeBService;
    @Resource
    ServiceItemTimeConfigService serviceItemTimeConfigService;
    @Resource
    ServiceGroupService serviceGroupService;
    @Resource
    ItemCategoryService itemCategoryService;
    @Resource
    ServProductBService servProductBService;
    @Resource
    BaseCategoryService baseCategoryService;
    @Resource
    ServCategoryService servCategoryService;
    @Resource
    ProductTariffService productTariffService;
    @Resource
    BaseCategoryAttributeEnumService baseCategoryAttributeEnumService;

    private static final String ON_ORDER_TARIFFID = "0";

    // 产品属性本地缓存
    private Cache<Integer, String> productEnuCache = CacheBuilder.newBuilder().expireAfterWrite(240, TimeUnit.HOURS).build();

    @Override
    @Cacheable(cacheNames = "redis5m", key = "'price:listItemPriceByQuery:ItemPriceQuery:'+#p0", unless = "#result == null")
    public List<ItemTo> listItemPriceByQuery(ItemPriceQuery query) {

        Integer productId = query.getProductId();
        Integer showType = query.getShowType();
        Integer channelId = query.getChannelId(); // 原始渠道id,试点使用该字段
        Integer cityId = query.getCityId();
        Integer bizType = query.getBizType();
        Integer tariffId = query.getTariffId();
        ServProduct servProduct = servProductService.findByKeyWithCache(productId);
        if (Objects.isNull(servProduct)) {
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_SERVICE_PRODUCT_NULL);
        }
        if (NumberUtil.isNullOrZero(showType)) {
            showType = servProduct.getShowType();
        }

        // 服务分类名称
        ServCategory servCateg = servCategoryService.findByKey(servProduct.getServCategId());

        List<ItemTo> itemDROS = new ArrayList<>();
        // 特殊服务项
        if (!CollectionUtils.isEmpty(query.getIdList())) {
            ProductItemQuery itemQuery2 = new ProductItemQuery();
            itemQuery2.setTariffIds(query.getIdList());
            List<ItemTo> itemTosSpe = productTariffGroupItemService.listItemPriceByQuery(itemQuery2).stream()
                    .peek(e -> {
                        e.setGroupName(ProductConsts.SERVICE_ITEM_COMMON_ADJUST_GROUP_NAME);
                        e.setGroupId(ProductConsts.SERVICE_ITEM_COMMON_ADJUST_GROUP_ID);
                    })
                    .collect(Collectors.toList());
            itemDROS.addAll(itemTosSpe);
        }

        // 查询前台、后台、计价器产品关系
        List<ProductRelationDTO> relationDTOList = Optional.ofNullable
                (servProductBService.listProductRalationByIdListAndShowType(Arrays.asList(productId), showType))
                .orElse(Collections.emptyList());

        if (NumberUtil.isNullOrZero(tariffId)) {
            if (Objects.equals(ON_ORDER_TARIFFID, String.valueOf(tariffId))) {
                // 在途订单,只考虑计价器价格表（兼容线上环境，后续可删除）
                commonBService.getTariffByOnOrder(relationDTOList, channelId, cityId, bizType);
                log.info("在途订单，兼容处理后的产品关系价格表relationDTOList：{}", relationDTOList);
            } else {
                // 根据渠道城市查询产品的价格表id和类型
                commonBService.getTariffByPilot(relationDTOList, channelId, cityId, bizType);
                log.info("计算后的产品关系价格表relationDTOList：{}", relationDTOList);

                // 筛选出价格表优先的数据
                commonBService.filterTariff(relationDTOList, ProductConsts.EC_PRODUCT_TYPE, false);
                log.info("筛选出价格表优先的数据relationDTOList：{}", relationDTOList);
            }
        } else {
            // 带订单（有价格表）
            relationDTOList.forEach(e -> e.setTariffId(tariffId));
        }

        // 走系数定价
        List<KvDTO<Integer, Integer>> listRatio = new ArrayList<>(relationDTOList.size());
        // 走城市定价
        List<KvDTO<Integer, Integer>> listCity = new ArrayList<>(relationDTOList.size());

        for (ProductRelationDTO relationDTO : relationDTOList) {
            if (NumberUtil.isNullOrZero(relationDTO.getTariffId())) {
                continue;
            }
            // 查询价格表
            ServiceTariff tariff = serviceTariffService.findByKeyWithCache(relationDTO.getTariffId());
            if (Objects.isNull(tariff)) {
                continue;
            }
            KvDTO kvDTO = new KvDTO(relationDTO.getProductId(), relationDTO.getTariffId());
            if (Objects.equals(tariff.getPriceType(), ProductDict.TRIFF_PRICE_TYPE_CITY)) {
                listCity.add(kvDTO);
            } else {
                listRatio.add(kvDTO);
            }
        }

        // 查询item集合
        List<ItemTo> itemToList = new ArrayList<>(relationDTOList.size());
        ProductItemQuery itemQuery = new ProductItemQuery();
        if (!CollectionUtils.isEmpty(listRatio)) {
            // 系数定价item
            itemQuery.setKvList(listRatio);
            List<ItemTo> itemTos = productTariffGroupItemService.listItemPriceByQuery(itemQuery);
            if (itemTos != null) {
                itemToList.addAll(itemTos);
            }
        }
        if (!CollectionUtils.isEmpty(listCity)) {
            // 城市定价item
            itemQuery.setKvList(listCity);
            itemQuery.setCityId(query.getCityId());
            List<ItemTo> itemTos = productTariffItemCityPriceService.listItemPriceByQuery(itemQuery);
            if (itemTos != null) {
                itemToList.addAll(itemTos);
            }
        }
        log.info("项目itemToList:{}", itemToList);
        if (CollectionUtils.isEmpty(itemToList)) {
            return itemDROS;
        }
        // 添加时间段限制
        if (Objects.nonNull(query.getServiceTime())) {
            // 排除在当前时间不显示的项目
            List<Integer> notShowItemIds = serviceItemTimeConfigService.listNotShowItemByTime(query.getServiceTime());
            if (!CollectionUtils.isEmpty(notShowItemIds)) {
                itemToList = itemToList.stream().filter(e -> !notShowItemIds.contains(e.getItemId())).collect(Collectors.toList());
            }
        }

        // 入参传入分公司时需要取分公司的服务时长，没有配置分公司服务时长则取通用时长
        List<Integer> itemIds = itemToList.stream().map(ItemTo::getItemId).collect(Collectors.toList());
        Map<Integer, Integer> maps = serviceTimeBService.setServiceDuration(itemIds, query.getCompanyId());

        PriceCalDTO calDTO = new PriceCalDTO(query.getChannelId(), query.getCityId(), query.getBrandId(), query.getBizType(), query.getDifficultId());

        // 后台产品Map
        List<Integer> productIdList = itemToList.stream().map(m -> m.getProductId()).distinct().collect(Collectors.toList());
        List<ServProduct> products = servProductService.listByIdList(productIdList);
        Map<Integer, ServProduct> productMap = Optional.ofNullable(products)
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.toMap(ServProduct::getProductId, r -> r));

        // 二级分类Map
        List<Integer> categTwoIdList = products.stream().map(m -> m.getCategId()).distinct().collect(Collectors.toList());
        Map<Integer, BaseCategory> categTwoMap = Optional.ofNullable(baseCategoryService.findByKeys(categTwoIdList))
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.toMap(BaseCategory::getCategId, r -> r));


        // 分组Map
        List<Integer> groupIdList = itemToList.stream().map(m -> m.getGroupId()).distinct().collect(Collectors.toList());
        Map<Integer, ServiceGroup> groupMap = Optional.ofNullable(serviceGroupService.listByGroupIds(groupIdList))
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.toMap(ServiceGroup::getGroupId, r -> r));

        // 故障类型排序Map
        List<Integer> categIdList = itemToList.stream().map(m -> m.getCategId()).distinct().collect(Collectors.toList());
        Map<Integer, Integer> categSortMap = Optional.ofNullable(itemCategoryService.listByKeys(categIdList))
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.toMap(ItemCategory::getCategId, ItemCategory::getSort));

        // 查询后台产品与价格表关系
        ProductTariffQuery productTariffQuery = new ProductTariffQuery();
        productTariffQuery.setProductId(productIdList.get(0));
        productTariffQuery.setTariffId(itemToList.get(0).getTariffId());
        productTariffQuery.setStatus(GlobalConsts.YES);
        ProductTariffVO productTariff = productTariffService.listByQueryWithCache(productTariffQuery)
                .stream()
                .findFirst()
                .orElse(new ProductTariffVO());

        // 设置分组和类型的排序并按照itemId排序
        List<ItemTo> newItemToList = itemToList.parallelStream()
                .peek(m -> {
                    if (!CollectionUtils.isEmpty(maps)) {
                        m.setServiceMinutes(NumberUtil.isNullOrZero(maps.get(m.getItemId())) ? m.getServiceMinutes() : maps.get(m.getItemId()));
                    }
                    // 设置定价方式(计算价格前需设置定价方式)
                    ServiceTariff tariff = serviceTariffService.findByKeyWithCache(m.getTariffId());
                    m.setTariffName(tariff.getTariffName());
                    m.setTariffType(tariff.getTariffType());
                    m.setPriceType(tariff.getPriceType());

                    // 计算单价
                    commonBService.calPriceDetail(m, calDTO);
                    log.info("项目itemTo计算价格后数据:{},价格表类型:{}", m);

                    m.setProductName(productMap.get(m.getProductId()).getName());
                    m.setProductSort(productMap.get(m.getProductId()).getSort());
                    m.setServCategName(servCateg.getName());
                    m.setCategId(productMap.get(m.getProductId()).getCategId());
                    m.setCategName(categTwoMap.get(m.getCategId()).getName());
                    m.setCategSort(categTwoMap.get(m.getCategId()).getSort());
                    m.setGroupName(groupMap.get(m.getGroupId()).getGroupName());
                    m.setGroupSort(groupMap.get(m.getGroupId()).getSort());
                    m.setItemCategSort(categSortMap.get(m.getItemCategId()));
                    m.setDesc(productTariff.getDesc());
                })
                .sorted(Comparator.comparing(ItemTo::getItemId))
                .collect(Collectors.toList());
        itemDROS.addAll(newItemToList);
        return itemDROS;
    }

    @Override
    @Cacheable(cacheNames = "redis5m", key = "'price:listItemPriceTransByQuery:ItemPriceQuery:'+#p0", unless = "#result == null")
    public List<ItemTo> listItemPriceTransByQuery(ItemPriceQuery query) {

        Integer productId = query.getProductId();
        Integer showType = query.getShowType();
        Integer channelId = query.getChannelId(); // 原始渠道id,试点使用该字段
        Integer cityId = query.getCityId();
        Integer bizType = query.getBizType();
        Integer tariffId = query.getTariffId();
        ServProduct servProduct = servProductService.findByKeyWithCache(productId);
        if (Objects.isNull(servProduct)) {
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_SERVICE_PRODUCT_NULL);
        }
        if (NumberUtil.isNullOrZero(showType)) {
            showType = servProduct.getShowType();
        }

        // 服务分类
        ServCategory servCateg = servCategoryService.findByKey(servProduct.getServCategId());

        List<ItemTo> itemDROS = new ArrayList<>();
        // 特殊服务项
        if (!CollectionUtils.isEmpty(query.getIdList())) {
            ProductItemQuery itemQuery2 = new ProductItemQuery();
            itemQuery2.setTariffIds(query.getIdList());
            List<ItemTo> itemTosSpe = productTariffGroupItemService.listItemPriceByQuery(itemQuery2).stream()
                    .peek(e -> {
                        e.setGroupName(ProductConsts.SERVICE_ITEM_COMMON_ADJUST_GROUP_NAME);
                        e.setGroupId(ProductConsts.SERVICE_ITEM_COMMON_ADJUST_GROUP_ID);
                    })
                    .collect(Collectors.toList());
            itemDROS.addAll(itemTosSpe);
        }

        // 查询前台、后台、计价器产品关系
        List<ProductRelationDTO> relationDTOList = Optional.ofNullable
                (servProductBService.listProductRalationByIdListAndShowType(Arrays.asList(productId), showType))
                .orElse(Collections.emptyList());

        if (NumberUtil.isNullOrZero(tariffId)) {
            if (Objects.equals(ON_ORDER_TARIFFID, String.valueOf(tariffId))) {
                // 在途订单,只考虑计价器价格表（兼容线上环境，后续可删除）
                commonBService.getTariffByOnOrder(relationDTOList, channelId, cityId, bizType);
                log.info("在途订单，兼容处理后的产品关系价格表relationDTOList：{}", relationDTOList);
            } else {
                // 根据渠道城市查询产品的价格表id和类型
                commonBService.getTariffByPilot(relationDTOList, channelId, cityId, bizType);
                log.info("计算后的产品关系价格表relationDTOList：{}", relationDTOList);

                // 筛选出价格表优先的数据
                commonBService.filterTariff(relationDTOList, ProductConsts.EC_PRODUCT_TYPE, false);
                log.info("筛选出价格表优先的数据relationDTOList：{}", relationDTOList);
            }
        } else {
            // 带订单（有价格表）
            relationDTOList.forEach(e -> e.setTariffId(tariffId));
        }

        // 走系数定价
        List<KvDTO<Integer, Integer>> listRatio = new ArrayList<>(relationDTOList.size());
        // 走城市定价
        List<KvDTO<Integer, Integer>> listCity = new ArrayList<>(relationDTOList.size());

        for (ProductRelationDTO relationDTO : relationDTOList) {
            if (NumberUtil.isNullOrZero(relationDTO.getTariffId())) {
                continue;
            }
            // 查询价格表
            ServiceTariff tariff = serviceTariffService.findByKeyWithCache(relationDTO.getTariffId());
            if (Objects.isNull(tariff)) {
                continue;
            }
            KvDTO kvDTO = new KvDTO(relationDTO.getProductId(), relationDTO.getTariffId());
            if (Objects.equals(tariff.getPriceType(), ProductDict.TRIFF_PRICE_TYPE_CITY)) {
                listCity.add(kvDTO);
            } else {
                listRatio.add(kvDTO);
            }
        }

        // 查询item集合
        List<ItemTo> itemToList = new ArrayList<>(relationDTOList.size());
        ProductItemQuery itemQuery = new ProductItemQuery();
        if (!CollectionUtils.isEmpty(listRatio)) {
            // 系数定价item
            itemQuery.setKvList(listRatio);
            List<ItemTo> itemTos = productTariffGroupItemService.listItemPriceByQuery(itemQuery);
            if (itemTos != null) {
                itemToList.addAll(itemTos);
            }
        }
        if (!CollectionUtils.isEmpty(listCity)) {
            // 城市定价item
            itemQuery.setKvList(listCity);
            itemQuery.setCityId(query.getCityId());
            List<ItemTo> itemTos = productTariffItemCityPriceService.listItemPriceByQuery(itemQuery);
            if (itemTos != null) {
                itemToList.addAll(itemTos);
            }
        }
        log.info("项目itemToList:{}", itemToList);
        if (CollectionUtils.isEmpty(itemToList)) {
            return itemDROS;
        }
        // 添加时间段限制
        if (Objects.nonNull(query.getServiceTime())) {
            // 排除在当前时间不显示的项目
            List<Integer> notShowItemIds = serviceItemTimeConfigService.listNotShowItemByTime(query.getServiceTime());
            if (!CollectionUtils.isEmpty(notShowItemIds)) {
                itemToList = itemToList.stream().filter(e -> !notShowItemIds.contains(e.getItemId())).collect(Collectors.toList());
            }
        }

        // 入参传入分公司时需要取分公司的服务时长，没有配置分公司服务时长则取通用时长
        List<Integer> itemIds = itemToList.stream().map(ItemTo::getItemId).collect(Collectors.toList());
        Map<Integer, Integer> maps = serviceTimeBService.setServiceDuration(itemIds, query.getCompanyId());

        PriceCalDTO calDTO = new PriceCalDTO(query.getChannelId(), query.getCityId(), query.getBrandId(), query.getBizType(), query.getDifficultId());

        // 后台产品Map
        List<Integer> productIdList = itemToList.stream().map(m -> m.getProductId()).distinct().collect(Collectors.toList());
        List<ServProduct> products = servProductService.listByIdList(productIdList);
        Map<Integer, ServProduct> productMap = Optional.ofNullable(products)
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.toMap(ServProduct::getProductId, r -> r));

        // 二级分类Map
        List<Integer> categTwoIdList = products.stream().map(m -> m.getCategId()).distinct().collect(Collectors.toList());
        Map<Integer, BaseCategory> categTwoMap = Optional.ofNullable(baseCategoryService.findByKeys(categTwoIdList))
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.toMap(BaseCategory::getCategId, r -> r));


        // 分组Map
        List<Integer> groupIdList = itemToList.stream().map(m -> m.getGroupId()).distinct().collect(Collectors.toList());
        Map<Integer, ServiceGroup> groupMap = Optional.ofNullable(serviceGroupService.listByGroupIds(groupIdList))
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.toMap(ServiceGroup::getGroupId, r -> r));

        // 故障类型排序Map
        List<Integer> categIdList = itemToList.stream().map(m -> m.getCategId()).distinct().collect(Collectors.toList());
        Map<Integer, Integer> categSortMap = Optional.ofNullable(itemCategoryService.listByKeys(categIdList))
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.toMap(ItemCategory::getCategId, ItemCategory::getSort));

        // 查询后台产品与价格表关系
        ProductTariffQuery productTariffQuery = new ProductTariffQuery();
        productTariffQuery.setProductId(productIdList.get(0));
        productTariffQuery.setTariffId(itemToList.get(0).getTariffId());
        productTariffQuery.setStatus(GlobalConsts.YES);
        ProductTariffVO productTariff = productTariffService.listByQueryWithCache(productTariffQuery)
                .stream()
                .findFirst()
                .orElse(new ProductTariffVO());


        // 设置分组和类型的排序并按照itemId排序
        List<ItemTo> newItemToList = itemToList.parallelStream()
                .peek(m -> {
                    if (!CollectionUtils.isEmpty(maps)) {
                        m.setServiceMinutes(NumberUtil.isNullOrZero(maps.get(m.getItemId())) ? m.getServiceMinutes() : maps.get(m.getItemId()));
                    }
                    // 设置定价方式(计算价格前需设置定价方式)
                    ServiceTariff tariff = serviceTariffService.findByKeyWithCache(m.getTariffId());
                    m.setTariffName(tariff.getTariffName());
                    m.setTariffType(tariff.getTariffType());
                    m.setPriceType(tariff.getPriceType());

                    // 计算单价
                    commonBService.calPriceDetail(m, calDTO);
                    log.info("项目itemTo计算价格后数据:{},价格表类型:{}", m);

                    m.setProductName(productMap.get(m.getProductId()).getName());
                    m.setProductSort(productMap.get(m.getProductId()).getSort());
                    m.setServCategName(servCateg.getName());
                    m.setCategId(productMap.get(m.getProductId()).getCategId());
                    m.setCategName(categTwoMap.get(m.getCategId()).getName());
                    m.setCategSort(categTwoMap.get(m.getCategId()).getSort());
                    m.setGroupName(groupMap.get(m.getGroupId()).getGroupName());
                    m.setGroupSort(groupMap.get(m.getGroupId()).getSort());
                    m.setItemCategSort(categSortMap.get(m.getItemCategId()));
                    m.setDesc(productTariff.getDesc());
                    m.setSpecialDesc(productTariff.getSpecialDesc());

                    // 前台产品的属性值需要进行变换，具体的变化规则为：
                    // 1.项目名称：后台产品二级分类名称+产品属性
                    // 2.项目分组：项目名称
                    // 3.产品名称：前台产品名称
                    if (Objects.equals(ProductConsts.EC_PRODUCT_TYPE, servProduct.getShowType()) || Objects.equals(ProductConsts.ET_PRODUCT_TYPE, servProduct.getShowType())) {
                        m.setGroupName(m.getItemName());
                        m.setItemName(getSeqName(m.getProductId(), productMap.get(m.getProductId()).getSequence(), m.getCategId()));
                        m.setProductName(servProduct.getName());
                        m.setServCategName(servCateg.getShowName());
                    }
                })
                .sorted(Comparator.comparing(ItemTo::getItemId))
                .collect(Collectors.toList());
        itemDROS.addAll(newItemToList);
        return itemDROS;
    }

    @Override
    public List<ItemPriceDRO> listTotalPriceByDIO(List<ItemPriceDIO> list) {

        if (CollectionUtils.isEmpty(list)) {
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }
        List<ItemPriceDRO> dros = BeanCopyUtils.copyProperties(list, ItemPriceDIO.class, ItemPriceDRO.class, ItemPriceDRO::new);

        for (ItemPriceDRO dro : dros) {
            Integer itemId = dro.getItemId();
            Integer number = dro.getNumber();
            Integer price = dro.getPrice();
            if (NumberUtil.isNullOrZero(itemId) || NumberUtil.isNullOrZero(price) || NumberUtil.isNullOrZero(number)) {
                dro.setFianlMessage("参数不合法");
                continue;
            }
            // 查询项目
            ServiceItem item = serviceItemService.findByKey(itemId);
            if (Objects.isNull(item)) {
                dro.setFianlMessage("项目不存在");
                continue;
            }

            // 传入的item不是阶梯价，那么返回原始价格*数量
            BigDecimal orgPriceOne = new BigDecimal(price);
            BigDecimal numberB = new BigDecimal(number);
            BigDecimal orgPriceTotal = orgPriceOne.multiply(numberB);
            Integer intPriceTotal = orgPriceTotal.setScale(0, BigDecimal.ROUND_DOWN)
                    .divide(new BigDecimal(ProductDict.HUNDRED), 2, RoundingMode.HALF_UP).setScale(0, RoundingMode.HALF_UP).intValue() * ProductDict.HUNDRED;
            if (Objects.isNull(item.getPriceSplitType()) || Objects.equals(item.getPriceSplitType(), GlobalConsts.NO)) {
                dro.setTotalPrice(intPriceTotal);
                dro.setFianlMessage("不是阶梯价定价方式");
                continue;
            }

            // 计算阶梯价,材料费=价格*材料费百分比，工艺费=价格-材料费,阶梯的优惠在于对工艺费的优惠
            Integer numberStep = item.getNumberStep();
            Integer materialFee = item.getMaterialFee();
            if (!NumberUtil.isPositiveInteger(numberStep) || !NumberUtil.isPositiveInteger(materialFee)) {
                dro.setTotalPrice(intPriceTotal);
                dro.setFianlMessage("itemId对应的项目数量阶梯值或者材料费率不合法");
                continue;
            }
            // 材料费率，工艺费率
            BigDecimal materialFeePercent = new BigDecimal(materialFee).divide(new BigDecimal(ProductDict.HUNDRED)).setScale(2, BigDecimal.ROUND_HALF_UP);
            BigDecimal artFeePercent = BigDecimal.ONE.subtract(materialFeePercent);

            // 1.数量小于阶梯，价格不变
            if (number < numberStep) {
                dro.setTotalPrice(intPriceTotal);
                dro.setTotalMaterialPrice(orgPriceTotal.multiply(materialFeePercent).intValue() / 100 * 100);
                dro.setTotalArtPrice(intPriceTotal - dro.getTotalMaterialPrice());
                dro.setFianlMessage("数量没有达到阶梯值限制");
                continue;
            }

            // 2.大于等于的情况下才计算阶梯
            Integer baseDiscount = item.getBaseDiscount();
            Integer numberStepDown = item.getNumberStepDown();
            if (!NumberUtil.isPositiveInteger(baseDiscount) || !NumberUtil.isPositiveInteger(numberStepDown)) {
                dro.setTotalPrice(intPriceTotal);
                dro.setFianlMessage("itemId对应的数据底折或者阶梯值降幅不合法");
                continue;
            }
            //底折，阶梯值降幅
            BigDecimal baseDiscountPercent = new BigDecimal(baseDiscount).divide(new BigDecimal(ProductDict.HUNDRED)).setScale(2, BigDecimal.ROUND_HALF_UP);
            BigDecimal numberStepDownPercent = new BigDecimal(numberStepDown).divide(new BigDecimal(ProductDict.HUNDRED)).setScale(2, BigDecimal.ROUND_HALF_UP);
            // 比较（1-数量/数量阶梯值*阶梯降幅）和底折的大小，比底折小，那么取底折
            BigDecimal mub = numberB.divide(new BigDecimal(numberStep), 2, BigDecimal.ROUND_HALF_UP).setScale(0, BigDecimal.ROUND_DOWN);
            BigDecimal result = BigDecimal.ONE.subtract(mub.multiply(numberStepDownPercent));
            if (result.compareTo(baseDiscountPercent) < 0) {
                result = baseDiscountPercent;
            }
            // 单价 = 材料费+工艺费
            // 材料费保持不变
            BigDecimal materialFeeB = orgPriceOne.multiply(materialFeePercent);
            // 工艺费需要打折
            BigDecimal artFeeDiscountPercent = artFeePercent.multiply(result);
            BigDecimal artFeeB = orgPriceOne.multiply(artFeeDiscountPercent);
            // 最终单价
            BigDecimal oneFinalPrice = materialFeeB.add(artFeeB);
            BigDecimal total = oneFinalPrice.multiply(numberB).setScale(0, BigDecimal.ROUND_HALF_UP);
            // 总价需要四舍五入保留整数
            total = total.divide(new BigDecimal(ProductDict.HUNDRED), 2, RoundingMode.HALF_UP).setScale(0, RoundingMode.HALF_UP);
            Integer totalPrice = total.intValue() * ProductDict.HUNDRED;
            Integer materialFeeTotal = orgPriceTotal.multiply(materialFeePercent).intValue() / 100 * 100;
            Integer artFeeTotal = totalPrice - materialFeeTotal;

            dro.setTotalPrice(totalPrice);
            dro.setTotalMaterialPrice(materialFeeTotal);
            dro.setTotalArtPrice(artFeeTotal);
        }
        return dros;
    }

    private String getSeqName(Integer productId, String sequence, Integer categId) {
        try {
            return productEnuCache.get(productId, callerItem(sequence, categId));
        } catch (ExecutionException e) {
            log.error("getSeqName cache error.", e);
        }
        return null;
    }

    private Callable<String> callerItem(String sequence, Integer categId) {
        return () -> {
            List<Integer> attrIds = new ArrayList<>();
            if (StringUtil.isNotBlank(sequence) && sequence.indexOf("&") != -1) {
                String[] seqArray = sequence.split(",");
                for (String seq : seqArray) {
                    if (StringUtil.isNotBlank(seq) && seq.indexOf("&") != -1) {
                        String[] enumIdArray = seq.split("&");
                        if (enumIdArray.length > 1 && !Objects.equals(enumIdArray[0], enumIdArray[1])) {
                            attrIds.add(Integer.valueOf(enumIdArray[1]));
                        }
                    }
                }
            }
            List<BaseCategoryAttributeEnum> enumList = new ArrayList<>();
            if (!CollectionUtils.isEmpty(attrIds)) {
                enumList = baseCategoryAttributeEnumService.listByKeys(attrIds);
            }
            StringBuilder stringBuilder = new StringBuilder();
            if (CollectionUtils.isEmpty(enumList)) {
            } else {
                enumList.forEach(e -> {
                    stringBuilder.append(e.getEnumValue()).append(",");
                });
                if (stringBuilder.length() > 0) {
                    stringBuilder.deleteCharAt(stringBuilder.length() - 1);
                }
            }
            String name = Optional.ofNullable(baseCategoryService.findByKey(categId).getName()).orElse("");
            return name + stringBuilder.toString();
        };
    }


}
